/**
 * Copyright (C) 2010-2016 eBusiness Information, Excilys Group
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed To in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.ohosannotations.logger.appender;

import org.ohosannotations.OhosAnnotationsEnvironment;
import org.ohosannotations.Option;
import org.ohosannotations.internal.helper.FileHelper;
import org.ohosannotations.logger.Level;
import org.ohosannotations.logger.Logger;
import org.ohosannotations.logger.LoggerContext;
import org.ohosannotations.logger.LoggerFactory;
import org.ohosannotations.logger.formatter.FormatterFull;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.annotation.processing.Messager;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.tools.Diagnostic.Kind;

/**
 * 文件目的地
 *
 * @author dev
 * @since 2021-07-22
 */
public class FileAppender extends Appender {
    /**
     * 选择日志文件
     */
    public static final Option OPTION_LOG_FILE = new Option("logFile", null);
    private static final String DEFAULT_FILENAME = "ohosannotations.log";
    private static final Logger LOGGER = LoggerFactory.getLogger(FileAppender.class);
    private File file;
    private FileOutputStream outputStream;

    /**
     * 文件目的地
     */
    public FileAppender() {
        super(new FormatterFull());
    }

    @Override
    public synchronized void open() {
        if (!isStreamOpened()) {
            try {
                outputStream = new FileOutputStream(file, true);
            } catch (FileNotFoundException error) {
                LOGGER.error(" open FileNotFoundException ", error.getLocalizedMessage());
            }
        }
    }

    @Override
    public synchronized void close(boolean isLastRound) {
        if (isStreamOpened()) {
            try {
                outputStream.close();
            } catch (IOException error) {
                LOGGER.error(" close IOException ", error.getLocalizedMessage());
            }
            outputStream = null;
        }
    }

    @Override
    public synchronized void append(Level level, Element element, AnnotationMirror annotationMirror, String message) {
        String tempMessage = message;
        if (isStreamOpened()) {
            try {
                tempMessage += System.lineSeparator();
                outputStream.write(tempMessage.getBytes("UTF-8"));
                outputStream.flush();
            } catch (IOException error) {
                LOGGER.error(" append IOException ", error.getLocalizedMessage());
            }
        }
    }

    @Override
    public void setEnvironment(OhosAnnotationsEnvironment environment) {
        super.setEnvironment(environment);
        resolveLogFile(environment);
    }

    private void resolveLogFile(OhosAnnotationsEnvironment environment) {
        String logFile = environment.getOptionValue(OPTION_LOG_FILE);
        try {
            if (logFile != null) {
                file = resolveLogFileInSpecifiedPath(logFile);
            } else {
                file = resolveLogFileInParentsDirectories();
            }
        } catch (FileNotFoundException exception) {
            file = null;
        }

        Level logLevel = LoggerContext.getInstance().getCurrentLevel();
        Messager messager = processingEnv.getMessager();
        if (file == null) {
            if (Level.WARN.isGreaterOrEquals(logLevel)) {
                messager.printMessage(Kind.WARNING, "Can't resolve log file");
            }
        } else if (Level.INFO.isGreaterOrEquals(logLevel)) {
            try {
                messager.printMessage(Kind.NOTE, "Resolve log file to " + file.getCanonicalPath());
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
        }
    }

    private File resolveLogFileInSpecifiedPath(String logFile) throws FileNotFoundException {
        File outputDirectory = FileHelper.resolveOutputDirectory(processingEnv);
        try {
            logFile = logFile.replace("{outputFolder}", outputDirectory.getCanonicalPath());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new File(logFile);
    }


    private File resolveLogFileInParentsDirectories() throws FileNotFoundException {
        File outputDirectory = FileHelper.resolveOutputDirectory(processingEnv);
        return new File(outputDirectory, DEFAULT_FILENAME);
    }

    private boolean isStreamOpened() {
        return outputStream != null;
    }
}
